package yxy.game.pm2.chat.module;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.joda.time.DateTime;
import org.redisson.api.RList;
import org.redisson.api.RSet;

import yxy.cherry.game.base.message.MessageEmitterHandler;
import yxy.game.pm2.bean.PlayerBean;
import yxy.game.pm2.bean.area.ChatChannelType;
import yxy.game.pm2.bean.module.BaseGameRedisBean;
import yxy.game.pm2.message.ChatMessage;

abstract public class BaseChatChannelModule extends BaseGameRedisBean {
	// bean===========================================================================

	// func===========================================================================

	abstract protected ChatChannelType getChannelType();

	/** 历史记录保存数量 -1表示不删除历史记录 */
	abstract protected int historySize();

	public void register(PlayerBean playerBean) {
		try {
			if (tryLock()) {
				touchSubscriber().add(String.valueOf(playerBean.getUid()));
			}
		} catch (Exception e) {
		} finally {
			unlock();
		}
	}

	public void logout(PlayerBean playerBean) {
		try {
			if (tryLock()) {
				touchSubscriber().remove(String.valueOf(playerBean.getUid()));
			}
		} catch (Exception e) {
		} finally {
			unlock();
		}
	}

	public void send(ChatMsg msg) {
		add(msg);
		ChatMessage.ChatNotification notify = packNotification(msg);
		Set<String> subs = touchSubscriber().readAll();
		Set<String> unsuccessSubs = new HashSet<>();
		for (String uidString : subs) {
			int uid = Integer.parseInt(uidString);
			boolean success = MessageEmitterHandler.getInstance().send(uid, notify);
			if (!success) {
				unsuccessSubs.add(uidString);
			}
		}
		try {
			if (tryLock()) {
				RSet<String> subSet = touchSubscriber();
				for (String uidString : unsuccessSubs) {
					subSet.remove(uidString);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			unlock();
		}
	}

	public boolean checkInterval(String playerCode) {
		DateTime now = DateTime.now();
		List<ChatMsg> list = touch().readAll();
		for (ChatMsg msg : list) {
			if (!(msg instanceof ChatMsgPlayer)) {
				continue;
			}
			ChatMsgPlayer msgp = (ChatMsgPlayer) msg;
			if (msgp.getPlayerCode().equals(playerCode)) {
				if (now.isBefore(msgp.getTime().plusSeconds(10))) {
					return true;
				}
			}
		}
		return false;
	}

	public boolean checkIntervalOfBattle(String playerCode) {
		DateTime now = DateTime.now();
		List<ChatMsg> list = touch().readAll();
		for (ChatMsg msg : list) {
			if (!(msg instanceof ChatMsgPlayer)) {
				continue;
			}
			ChatMsgPlayer msgp = (ChatMsgPlayer) msg;
			if (msgp.getPlayerCode().equals(playerCode)) {
				if (now.isBefore(msgp.getTime().plusMinutes(5))) {
					return true;
				}
			}
		}
		return false;
	}

	private ChatMessage.ChatNotification packNotification(ChatMsg msg) {
		ChatMessage.ChatNotification.Builder builder = ChatMessage.ChatNotification.newBuilder();
		ChatMessage.ChatChannel channel = ChatMessage.ChatChannel.forNumber(getChannelType().getNumber());
		builder.setChannel(channel);
		builder.setMsg(msg.pack());
		return builder.build();
	}

	// redis==========================================================================

	abstract protected String key();

	abstract protected String keySub();

	protected RList<ChatMsg> touch() {
		return redis().client().getList(key());
	}

	protected RSet<String> touchSubscriber() {
		return redis().client().getSet(keySub());
	}

	protected void add(ChatMsg msg) {
		try {
			if (tryLock()) {
				RList<ChatMsg> list = touch();
				list.add(msg);

				if (list.size() > historySize() && historySize() > 0) {
					list.remove(0);
				}
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			unlock();
		}
	}

	public void clear() {
		touch().clear();
		touchSubscriber().clear();
	}

	public Collection<ChatMsg> all() {
		return touch().readAll();
	}

	// lock===========================================================================

	@Override
	public String lockKey() {
		return String.format("lock:%s", key());
	}

}
